// // Copyright (c) 2009 All Right Reserved // // vl // // 2009-01-01 // Contains ... namespace LargoCommon.Music { using Abstract; using JetBrains.Annotations; using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; using System.Text; using System.Xml.Linq; /// /// Harmonic Streams Port. /// public class MusicalOrchestration { #region Constructors /// /// Initializes a new instance of the class. /// public MusicalOrchestration() { this.OrchestraBlocks = new List(); } /// /// Initializes a new instance of the class. /// /// The given block. public MusicalOrchestration(MusicalBlock givenBlock) { this.ObjectName = givenBlock.FullName; this.Header = givenBlock.Header; this.OrchestraBlocks = new List(); var body = givenBlock.Body; //// ?!?!?! body.SetHarmonicBasis(this.BlockChanges); //// true var simpleChanges = body.ExtractSimpleChanges(MusicalChangeType.Instrument); //// var simpleChanges = this.BlockChanges.InstrumentChanges; var changedBarNumbers = (from ic in simpleChanges select ic.BarNumber).Distinct().ToList(); OrchestraBlock lastOrchestraBlock = null; var changedBars = from b in body.Bars where changedBarNumbers.Contains(b.BarNumber) select b; foreach (var bar in changedBars) { if (lastOrchestraBlock != null) { lastOrchestraBlock.BarNumberTo = bar.BarNumber - 1; } var strip = bar.OrchestraStrip(); var orchestraBlock = new OrchestraBlock(givenBlock.Header, bar.BarNumber, strip); this.OrchestraBlocks.Add(orchestraBlock); lastOrchestraBlock = orchestraBlock; } if (lastOrchestraBlock != null) { lastOrchestraBlock.BarNumberTo = givenBlock.Header.NumberOfBars; } } #endregion #region Public properties /// /// Gets or sets the header. /// /// /// The header. /// public MusicalHeader Header { get; set; } /// /// Gets or sets the name of the style. /// /// /// The name of the set. /// public string ObjectName { get; set; } /// /// Gets a value indicating whether is valid. /// /// /// true if this instance is valid; otherwise, false. /// [UsedImplicitly] public bool IsValid => this.OrchestraBlocks.Any(); /// /// Gets or sets the instrumentation of bars. /// /// /// Property description. /// public IList OrchestraBlocks { get; set; } #endregion #region Public static factory methods #endregion /// /// Orchestrates the specified given block. /// /// The given block. /// The area. /// The orchestra block. public static void Orchestrate(MusicalBlock givenBlock, MusicalSection area, OrchestraBlock orchestraBlock) { int line = -1; foreach (var mtrack in givenBlock.Strip.Lines) { line++; if (mtrack == null) { continue; } var track = orchestraBlock.Strip.OptimalOrchestraTrack(mtrack); if (track == null) { continue; } if (mtrack.FirstStatus != null) { mtrack.FirstStatus.CurrentOrchestraTrack = track; } if (mtrack.FirstStatus != null) { mtrack.FirstStatus.Instrument = track.Instrument; } var tones = mtrack.MusicalTonesInArea(area); tones.SetInstrument(track.InstrumentNumber, track.Octave); for (var bar = 1; bar <= givenBlock.Header.NumberOfBars; bar++) { var point = MusicalPoint.GetPoint(line, bar); //// 2017/03 !?!? //// var point = MusicalPoint.GetPoint(mtrack.LineIndex, bar); //// line var me = givenBlock.Body.GetElement(point); if (me == null) { continue; } me.Status.Instrument = track.Instrument; } track.IsUsed = true; } } #region String representation /// String representation of the object. /// Returns value. public override string ToString() { var s = new StringBuilder(); s.AppendFormat("Orchestra {0}", this.ObjectName); return s.ToString(); } #endregion #region Public methods /// /// Adds the content of the style. /// /// The orchestration. [UsedImplicitly] public void AddObjectContent(MusicalOrchestration orchestration) { //// this = style.HarmonicOrder; this.RhythmicOrder = style.RhythmicOrder; //// ??????? var ob = (List)this.OrchestraBlocks; ob.AddRange(orchestration.OrchestraBlocks); } /// /// Saves the style. /// /// The given folder. [UsedImplicitly] public void SaveToFolder(string givenFolder) { var tmpFolderPath = SupportFiles.GetTemporaryDirectory; Directory.CreateDirectory(tmpFolderPath); XElement xcomponent = new XElement( "Component", new XAttribute("Description", string.Empty), new XAttribute("Name", this.ObjectName), this.Header.GetXElement); var xdoc = new XDocument(new XDeclaration("1.0", "utf-8", null), xcomponent); xdoc.Save(Path.Combine(tmpFolderPath, @"Component.xml")); //// Orchestra Blocks var xblocks = this.WriteOrchestraBlocks(); xdoc = new XDocument(new XDeclaration("1.0", "utf-8", null), xblocks); //// var filepath = Path.Combine(givenPath, "RhythmicPatterns.xml"); xdoc.Save(Path.Combine(tmpFolderPath, @"OrchestraBlocks.xml")); var finalPath = Path.Combine(givenFolder, this.ObjectName.ClearSpecialChars() + ".orchestra"); ZipFile.CreateFromDirectory(tmpFolderPath, finalPath); //// ZipFileCover.CreateZipFileRecursive(tmpFolderPath, finalPath, false, true); Directory.Delete(tmpFolderPath, true); } #endregion #region Public methods - Orchestration /// /// Gets the orchestra block for. /// /// The number of melodic tracks. /// The number of rhythmic tracks. /// Orchestra block. /// /// Returns value. /// public OrchestraBlock GetOrchestraBlockFor(byte numberOfMelodicTracks, byte numberOfRhythmicTracks, OrchestraBlock previousBlock) { var trackCount = numberOfMelodicTracks + numberOfRhythmicTracks; var blockCount = this.OrchestraBlocks.Count; if (blockCount == 0) { return null; } OrchestraBlock optimalBlock = null; var maxvalue = 0; foreach (var block in this.OrchestraBlocks) { var value = 100 - Math.Abs(block.TrackCount - trackCount); if (block.TrackCount < trackCount) { value -= 20; } if (previousBlock != null && block.Name == previousBlock.Name) { value -= 10; } value += MathSupport.RandomNatural(10); if (value > maxvalue) { maxvalue = value; optimalBlock = block; } } return optimalBlock; ////var idx = MathSupport.RandomNatural(blockCount); //// return this.OrchestraBlocks[idx]; } /// /// Gets the orchestra block for - in simple (one block) styles. /// /// The given bar number. /// Returns value. [UsedImplicitly] public OrchestraBlock GetOrchestraBlockFor(int givenBarNumber) { if (!this.OrchestraBlocks.Any()) { return null; } var orchestraBlock = (from ob in this.OrchestraBlocks where ob.BarNumberFrom <= givenBarNumber && ob.BarNumberTo >= givenBarNumber select ob).FirstOrDefault(); return orchestraBlock; } /// /// Orchestrates the musical block. /// /// The given block. public void OrchestrateMusicalBlock(MusicalBlock givenBlock) { OrchestraBlock lastOBlock = null; //// Cycle through current orchestra blocks var orchestration = new MusicalOrchestration(givenBlock); foreach (var block in orchestration.OrchestraBlocks) { if (block == null) { continue; } var area = new MusicalSection(block.BarNumberFrom, block.BarNumberTo, string.Empty); //// this.blockEditor.NumberOfLines byte numberOfMelodicLines = (byte)givenBlock.Strip.Lines.Count; //// this.NumberOfUsedLines(area); #warning numberOfRhythmicLines byte numberOfRhythmicLines = 0; //// this.NumberOfUsedLines(area); //// To get ne orchestra block for the substitution var orchestraBlock = this.GetOrchestraBlockFor(numberOfMelodicLines, numberOfRhythmicLines, lastOBlock); lastOBlock = orchestraBlock; if (orchestraBlock == null) { return; } Orchestrate(givenBlock, area, orchestraBlock); } } #endregion #region Private static methods /// /// Initializes a new instance of the class. /// /// The given file path. /// Returns value. [UsedImplicitly] private static MusicalOrchestration GetOrchestration(string givenFilePath) { var style = new MusicalOrchestration(); var fileName = Path.GetFileNameWithoutExtension(givenFilePath); if (fileName == null) { return null; } style.ObjectName = fileName.Trim(); var tmpFolderPath = MusicalSettings.Singleton.Folders.GetTemporaryFolder; //// SupportFiles.GetTemporaryDirectory; if (tmpFolderPath == null) { return null; } ZipFile.ExtractToDirectory(givenFilePath, tmpFolderPath); //// ZipFileCover.UnzipFile(givenFilePath, tmpFolderPath); var fi = SupportFiles.LatestFile(tmpFolderPath, "*.xml"); if (fi == null) { if (Directory.Exists(tmpFolderPath)) { Directory.Delete(tmpFolderPath, true); } return null; } var root = XmlSupport.GetXDocRoot(Path.Combine(tmpFolderPath, "Component.xml")); if (root != null && root.Name == "Component") { var xstyle = root; //// var description = XmlSupport.ReadStringAttribute(xstyle.Attribute("Description")); //// unused var name = XmlSupport.ReadStringAttribute(xstyle.Attribute("Name")); style.Header = new MusicalHeader(xstyle.Element("Header")); //// this.HarmonicOrder = XmlSupport.ReadByteAttribute(xstyle.Attribute("HarmonicOrder")); //// this.RhythmicOrder = XmlSupport.ReadByteAttribute(xstyle.Attribute("RhythmicOrder")); } style.LoadOrchestraBlocks(Path.Combine(tmpFolderPath, "OrchestraBlocks.xml")); //// MusicalStyle.internalSingleton = this; if (Directory.Exists(tmpFolderPath)) { Directory.Delete(tmpFolderPath, true); } return style; } #endregion #region Private methods - Load finals /// /// Loads the orchestra model. /// /// The file path. private void LoadOrchestraBlocks(string filePath) { var root = XmlSupport.GetXDocRoot(filePath); if (root != null && root.Name == "OrchestraBlocks") { var xbundle = root; var xblocks = xbundle.Elements("Block"); var list = new List(); // ReSharper disable once LoopCanBeConvertedToQuery foreach (var xblock in xblocks) { var orchestraBlock = new OrchestraBlock(xblock); list.Add(orchestraBlock); } this.OrchestraBlocks = list; } } #endregion #region Private methods - Save final /// /// Writes the orchestra blocks. /// /// Returns value. private XElement WriteOrchestraBlocks() { XElement xblocks = new XElement( "OrchestraBlocks", new XAttribute("Description", string.Empty)); foreach (var orchestraBlock in this.OrchestraBlocks) { XElement xblock = orchestraBlock.GetXElement; xblocks.Add(xblock); } return xblocks; } #endregion } }